home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1996 / MacHack 1996.toast / Presentations / Presentations ’93 / Macintosh as Internet Server ƒ / inetd / in.rshd / in.rcp / rcp.cp < prev    next >
Text File  |  1993-04-08  |  12KB  |  593 lines

  1. //---------------------------------------------------------------------
  2. //
  3. //    Copyright © 1992 David Peterson.
  4. //    All rights reserved.
  5. //
  6. //    Permission to use, copy, modify, and distribute this software for
  7. //    any purpose and without fee is hereby granted, provided that the
  8. //    above copyright notice appear in all copies and that both that
  9. //    copyright notice and this permission notice appear in supporting
  10. //    documentation.
  11. //
  12. //---------------------------------------------------------------------
  13.  
  14. #include "rcp.h"
  15.  
  16. #include <UFailure.h>
  17.  
  18. #include <myUtils.h>
  19. #include <TCP.h>
  20.  
  21. #include <Sysequ.h>
  22. #include <Folders.h>
  23. #include <Packages.h>
  24. #include <String.h>
  25. #include <Strings.h>
  26. #include <Errors.h>
  27. #include <OSEvents.h>
  28. #include <StdLib.h>
  29. #include <ToolUtils.h>
  30. #include <CType.h>
  31. #include <Devices.h>
  32. #include <Resources.h>
  33. #include <StdIO.h>
  34.  
  35.  
  36.  
  37. void main();
  38.  
  39. void
  40. main()
  41. {
  42.     Rcp* aDaemon;
  43.  
  44.     InitUDaemonApp(*((long*) DefltStack));
  45.     
  46.     aDaemon = new Rcp;
  47.     
  48.     if (aDaemon) {
  49.         aDaemon->Initialize();
  50.         aDaemon->Run();
  51.  
  52.         {
  53.             AppleEvent    theEvent;
  54.             AEDesc        theAddress;
  55.             long        theType = 'inet';
  56.             OSErr        theErr    = noErr;
  57.             
  58.             AECreateDesc(typeApplSignature, (Ptr) &theType, sizeof(theType), &theAddress);
  59.             AECreateAppleEvent(kCoreEventClass, kAEApplicationDied,  &theAddress, kAutoGenerateReturnID, kAnyTransactionID, &theEvent);
  60.         
  61.             AEPutParamPtr(&theEvent, keyErrorNumber, typeLongInteger, (Ptr) &theErr, sizeof(long));
  62.             AEPutParamPtr(&theEvent, keyProcessSerialNumber, typeProcessSerialNumber, (Ptr) &(aDaemon->fPSN), sizeof(ProcessSerialNumber));
  63.         
  64.             DebugIfErr(AESend(&theEvent, nil, kAENoReply, kAEHighPriority, 0, nil, nil));
  65.         }
  66.         
  67.         delete aDaemon;
  68.     }
  69. }
  70.  
  71. Rcp::Rcp()
  72. {
  73.     fFileSize = 0;
  74.     fAmtLeft = 0;
  75.     fWorkingOnAFile = false;
  76.     fFileIORefNum = 0;
  77.     
  78.     fTargetShouldBeDir = false;
  79.     fTargetIsDir = false;
  80.     fIAmRecursive = false;
  81.     fToFlag = false;
  82.     fFromFlag = false;
  83.     
  84.     fVRefNum = 0;
  85.     fDirID = 0;
  86.     
  87.     fFileName[0] = 0;
  88.     
  89.     fBuffer = nil;
  90. }
  91.  
  92. Rcp::~Rcp()
  93. {
  94.     tcpClose(fStreamPtr);
  95.     
  96.     if (fBuffer) DisposePtr(fBuffer);
  97. }
  98.  
  99. void 
  100. Rcp::InstallAEHandlers()
  101. {
  102.     Inherited::InstallAEHandlers();
  103.  
  104.     FailOSErr(AEInstallEventHandler('INET', 'TSTR',
  105.                 (EventHandlerProcPtr) &AEStreamHandler, (long) this, false));
  106. }
  107.  
  108. void
  109. Rcp::Initialize()
  110. {
  111.     Inherited::Initialize();
  112.  
  113.     Handle    h;
  114.     int        size;
  115.     
  116.     h = GetResource('BUFF', 128);
  117.     if (h) 
  118.         size = *((int*) *h);
  119.     else
  120.         size = 2048;
  121.         
  122.     fBuffer = NewPtr(size);
  123.     fBufLen = size;
  124. }
  125.  
  126. pascal OSErr
  127. AEStreamHandler(AppleEvent* messagein, AppleEvent* /*reply*/, long refIn)
  128. {
  129.     OSErr        theErr = noErr;
  130.     Rcp*        daemon = (Rcp*) refIn;
  131.     AEDesc        streamDesc, commandDesc;
  132.         
  133.     if ((theErr = AEGetParamDesc(messagein, 'STRM', typeLongInteger, &streamDesc)) == noErr) {
  134.         HLock(streamDesc.dataHandle);
  135.         daemon->fStreamPtr = *((StreamPtr*) *(streamDesc.dataHandle));
  136.         HUnlock(streamDesc.dataHandle);
  137.  
  138.         AEDisposeDesc(&streamDesc);
  139.     }
  140.     
  141.     if ((theErr = AEGetParamDesc(messagein, 'CMND', typeChar, &commandDesc)) == noErr) {
  142.         HLock(commandDesc.dataHandle);
  143.         BlockMove(*(commandDesc.dataHandle), daemon->fCommandString, 256);
  144.         HUnlock(commandDesc.dataHandle);
  145.  
  146.         AEDisposeDesc(&commandDesc);
  147.     }
  148.     
  149.     daemon->TakeControlOfStream();
  150.     daemon->ParseCommandString();
  151.     
  152.     return theErr;
  153. }
  154.  
  155. void
  156. Rcp::TakeControlOfStream()
  157. {
  158.     AppleEvent    theEvent, myReply;
  159.     AEDesc        theAddress;
  160.     long        theType = 'inet';
  161.     ProcPtr        theProc = (ProcPtr) &Notify;
  162.     Rcp*        daemon    = this;
  163.  
  164.     AECreateDesc(typeApplSignature, (Ptr) &theType, sizeof(theType), &theAddress);
  165.     AECreateAppleEvent('INET', 'TNFY',  &theAddress, kAutoGenerateReturnID, kAnyTransactionID, &theEvent);
  166.     
  167.     AEPutParamPtr(&theEvent, 'STRM', typeLongInteger, (Ptr) &fStreamPtr, sizeof(StreamPtr));
  168.     AEPutParamPtr(&theEvent, 'ASR ', typeLongInteger, (Ptr) &theProc, sizeof(ProcPtr));
  169.     AEPutParamPtr(&theEvent, 'USRP', typeLongInteger, (Ptr) &daemon, sizeof(long));
  170.     AEPutParamPtr(&theEvent, keyProcessSerialNumber, typeProcessSerialNumber, (Ptr) &fPSN, sizeof(ProcessSerialNumber));
  171.     
  172.     FailOSErr(AESend(&theEvent, &myReply, kAEWaitReply + kAENeverInteract, kAEHighPriority, 120, nil, nil));
  173.  
  174.     FailOSErr(AEDisposeDesc(&myReply));
  175.     AEDisposeDesc(&theEvent);
  176.     AEDisposeDesc(&theAddress);
  177. }    
  178.  
  179. void
  180. Rcp::ParseCommandString()
  181. {
  182.     char*    cp;
  183.     short    vRefNum;
  184.     long    dirID;
  185.  
  186. //    MBPrintf("rcp: got: %s", fCommandString);
  187.  
  188.     cp = fCommandString;
  189.     cp += 4;    // skip over 'rcp ', now pointing to first dash
  190.     
  191.     while (*cp++ == '-') {        // points to option char now
  192.         switch (*cp++) {        // points to space after option char
  193.             case 'p':
  194.                 this->SendError("rcp: sorry, remote can't handle -p");
  195.                 return;
  196.             case 'f':
  197.                 this->SendError("rcp: sorry, can't fetch from here (yet)");
  198.                 return;
  199.                 fFromFlag = true;
  200.                 break;
  201.             case 'd':
  202.                 fTargetShouldBeDir = true;
  203.                 break;
  204.             case 'r':
  205.                 fIAmRecursive = true;
  206.                 fTargetShouldBeDir = true;
  207.                 break;
  208.             case 't':
  209.                 fToFlag = true;
  210.                 break;
  211.             default:
  212.                 this->SendError("rcp: unknown option");
  213.                 return;
  214.         }
  215.         
  216.         cp++;                    // points to next dash (if it exists)
  217.     }
  218.     cp--;                        // back up one (because next dash didn't exist)
  219.     
  220.     if (fToFlag && fFromFlag) {
  221.         this->SendError("rcp: don't do that");
  222.         return;
  223.     }
  224.     else if (fToFlag) {
  225.         fMore = (rcpProc) &Rcp::GetMore;
  226.         fFile = (rcpProc) &Rcp::NewFile;
  227.     }
  228.     else {
  229.         fMore = (rcpProc) &Rcp::ReadMore;
  230.         fFile = (rcpProc) &Rcp::OpenNext;
  231.     }
  232.     
  233.     this->VerifyAndSetDir(cp);
  234.  
  235.     HGetVol(nil, &vRefNum, &dirID);
  236.     
  237.     fVRefNum = vRefNum;
  238.     fDirID = dirID;
  239.  
  240.     this->SetSleepValue(1);
  241.     
  242.     this->SendOK();
  243. }
  244.  
  245. void
  246. Rcp::VerifyAndSetDir(char* targ)
  247. {
  248.     long        dirID;
  249.     short        refNum;
  250.     char*        targp;
  251.     Boolean        ondesk;
  252.     OSErr        theErr;
  253.     char        err[128];
  254.     FSSpec        spec;
  255.     FSSpec        spare;
  256.     CInfoPBRec    catinfo;
  257.     Boolean        isdir;
  258.     char        copy[128];
  259.     char*        copyp;
  260.     
  261.     if ((targ[0] == '.') && (targ[1] == '\0')) {
  262.         FindFolder(kOnSystemDisk, kDesktopFolderType, false, &refNum, &dirID);
  263.         HSetVol(nil, refNum, dirID);
  264.         return;
  265.     }
  266.     
  267.     targp = targ;
  268.     copyp = ©[1];
  269.     while (*targp) {
  270.         switch (*targp) {
  271.             case '/':
  272.                 *copyp = ':';
  273.                 break;
  274.             case ':':
  275.                 *copyp = '/';
  276.                 break;
  277.             case '*':
  278.             case '?':
  279.                 sprintf(err, "rcp: %s: wildcards not allowed", targ);
  280.                 this->SendError(err);
  281.                 return;
  282.             default:
  283.                 *copyp = *targp;
  284.         }
  285.             
  286.         copyp++;
  287.         targp++;
  288.     }
  289.     *copyp = 0;
  290.     
  291.     copyp = ©[1];
  292.     if (*copyp == ':') {
  293.         copyp++;
  294.         ondesk = false;
  295.     }
  296.     else {
  297.         *(--copyp) = ':';
  298.         ondesk = true;
  299.     }
  300.     c2pstr(copyp);
  301.     
  302. //    MBPrintf("copyp = %P", copyp);
  303.  
  304.     if (ondesk) {
  305.         FindFolder(kOnSystemDisk, kDesktopFolderType, false, &refNum, &dirID);
  306.         theErr = FSMakeFSSpec(refNum, dirID, (Str255) copyp, &spec);
  307.     }
  308.     else 
  309.         theErr = FSMakeFSSpec(0, 0, (Str255) copyp, &spec);
  310.     
  311. //    MBPrintf("spec = %P, %d, %d, err = %d", spec.name, spec.vRefNum, spec.parID, theErr);
  312.     
  313.     switch (theErr) {
  314.         case fnfErr:
  315.             if (fToFlag) {
  316.                 BlockMove(spec.name, fFileName, spec.name[0] + 1);
  317.                 HSetVol(nil, spec.vRefNum, spec.parID);
  318.                 return;
  319.             }
  320.         /* fall through if we're not recipient */
  321.         case dirNFErr:
  322.         case nsvErr:
  323.             sprintf(err, "rcp: %s: No such file or directory", targ);
  324.             this->SendError(err);
  325.             break;
  326.         case noErr:
  327.             FSMakeFSSpec(spec.vRefNum, spec.parID, spec.name, &spare);
  328.         
  329.             catinfo.hFileInfo.ioNamePtr = spare.name;
  330.             catinfo.hFileInfo.ioVRefNum = spare.vRefNum;
  331.             catinfo.hFileInfo.ioDirID = spare.parID;
  332.             catinfo.hFileInfo.ioFDirIndex = 0;
  333.             PBGetCatInfoSync(&catinfo);
  334.             
  335.             isdir = BitTst(&catinfo.hFileInfo.ioFlAttrib, 3);
  336.             if (isdir) {
  337.                 if (fToFlag)
  338.                     HSetVol(spec.name, spec.vRefNum, spec.parID);
  339.                 else if (fFromFlag && fIAmRecursive) {
  340.                     HSetVol(nil, spec.vRefNum, spec.parID);
  341.                     BlockMove(spec.name, fFileName, spec.name[0] + 1);
  342.                 }
  343.                 else {
  344.                     sprintf(err, "rcp: %s: not a plain file", targ);
  345.                     this->SendError(err);
  346.                     return;
  347.                 }
  348.             }
  349.             else {
  350.                 if (fToFlag && fTargetShouldBeDir) {
  351.                     sprintf(err, "rcp: %s: Not a directory", targ);
  352.                     this->SendError(err);
  353.                 }
  354.                 else {
  355.                     HSetVol(nil, spec.vRefNum, spec.parID);
  356.                     BlockMove(spec.name, fFileName, spec.name[0] + 1);
  357.                 }
  358.             }
  359.             break;
  360.         default:
  361.             sprintf(err, "rcp: %s: produced error", targ);
  362.             this->SendError(err);
  363.             break;
  364.     }
  365. }
  366.  
  367. void
  368. Rcp::DoNull()
  369. {
  370.     if (fWorkingOnAFile)
  371.         fMore(this);
  372.     else
  373.         fFile(this);
  374. }
  375.  
  376. void
  377. Rcp::GetMore()
  378. {
  379.     Ptr        buf = fBuffer;
  380.     short    len = (short) fBufLen;
  381.     
  382.     len = ((fAmtLeft < len) ? fAmtLeft : len);
  383.     
  384.     if (tcpRead(fStreamPtr, buf, &len) == noErr) {
  385.         fAmtLeft -= len;
  386.         this->WriteToFile(buf, len);
  387.         
  388.         if (fAmtLeft == 0) {
  389.             len = 1;
  390.             tcpRead(fStreamPtr, buf, &len);
  391.         
  392.             FSClose(fFileIORefNum);
  393.             fWorkingOnAFile = false;
  394.             this->SendOK();            
  395.         }
  396.     }
  397. }
  398.  
  399. void
  400. Rcp::ReadMore()
  401. {
  402.  
  403. }
  404.  
  405. void
  406. Rcp::NewFile()
  407. {
  408.     //    need to get description line
  409.     //    5 chars for file type/mode then space
  410.     //    file size in bytes (in ascii) then space
  411.     //    file name then newline
  412.     
  413.     short    len = 128;
  414.     Ptr        cp = fBuffer;
  415.     char    type = 0;
  416.     int        size = 0;
  417.     
  418.     tcpRead(fStreamPtr, cp, &len);
  419.     
  420. //    cp[len + 1] = 0;
  421. //    MBPrintf("newfile got: %s", cp);
  422.  
  423.     if (*cp == '\r') {
  424.         this->SendError("rcp: unexpected <newline>");
  425.         return;
  426.     }
  427.     else if (*cp == 'E') {
  428.         this->UpDir();
  429.         this->SendOK();
  430.         return;
  431.     }
  432.     else if ((*cp != 'C') && (*cp != 'D')) {
  433.         this->SendError("rcp: illegal file type");
  434.         return;
  435.     }
  436.     
  437.     type = *cp;
  438.     cp += 5;
  439.     
  440.     if (*cp++ != ' ') {
  441.         this->SendError("rcp: mode not delimited");
  442.         return;
  443.     }
  444.     
  445.     while (isdigit(*cp))
  446.         size = size * 10 + (*cp++ - '0');
  447.         
  448.     fFileSize = size;
  449.     fAmtLeft = size;
  450.     
  451.     if (*cp++ != ' ') {
  452.         this->SendError("rcp: size not delimited");
  453.         return;
  454.     }
  455.     
  456.     if (fFileName[0] == 0) {
  457.         char    namelen = 0;
  458.         char*    nameptr;
  459.     
  460.         nameptr = (char*) &fFileName[1];
  461.         while (*cp != '\r') {
  462.             *nameptr++ = *cp++;
  463.             namelen++;
  464.         }
  465.         fFileName[0] = namelen;
  466.     }
  467.     
  468.     if (fFileName[1] == '.')
  469.         fFileName[1] = '•';
  470.         
  471.     if (this->CreateFile((Str255) fFileName, type)) {
  472.         fFileName[0] = 0;
  473.         
  474.         if (type == 'C')
  475.             fWorkingOnAFile = true;
  476.         
  477.         this->SendOK();
  478.     }
  479. }
  480.  
  481. void
  482. Rcp::OpenNext()
  483. {
  484.  
  485. }
  486.  
  487. void
  488. Rcp::SendOK()
  489. {
  490.     tcpWrite(fStreamPtr, "", 1);
  491. }
  492.  
  493. void
  494. Rcp::SendError(char* msg)
  495. {
  496.     WDS(3)    wds;
  497.     char    no        = 1;
  498.  
  499.     wds.zero            = 0;
  500.     wds.block[0].ptr    = &no;
  501.     wds.block[0].length    = 1;
  502.     wds.block[1].ptr    = msg;
  503.     wds.block[1].length    = strlen(msg) + 1;
  504.     wds.block[2].ptr    = "\r";
  505.     wds.block[2].length    = 1;
  506.     
  507.     tcpWriteWDS(fStreamPtr, (wdsEntry*) &wds);
  508.     
  509.     this->DoQuit();
  510. }
  511.  
  512. Boolean
  513. Rcp::CreateFile(Str255 name, char type)
  514. {
  515.     FSSpec    spec;
  516.     long    dirID;
  517.     short    refNum;
  518.     OSErr    theErr    = noErr;
  519.     
  520.     FSMakeFSSpec(fVRefNum, fDirID, name, &spec);
  521.     
  522.     if (type == 'C') {
  523.         theErr = FSpCreate(&spec, 'MPS ', 'TEXT', smSystemScript);
  524.         if ((theErr == noErr) || (theErr == dupFNErr)) {
  525.             if (FSpOpenDF(&spec, fsRdWrPerm, &refNum) == noErr) {
  526.                 fFileIORefNum = refNum;
  527.                 if (theErr == dupFNErr)
  528.                     SetEOF(refNum, 0);
  529.             }
  530.             else
  531.                 this->SendError("rcp: couldn't open remote file");
  532.         }
  533.         else
  534.             this->SendError("rcp: couldn't create remote file");
  535.     }
  536.     else {
  537.         if ((theErr = FSpDirCreate(&spec, smSystemScript, &dirID)) == noErr) {
  538.             HSetVol(nil, fVRefNum, dirID);
  539.             fDirID = dirID;
  540.         }
  541.         else if (theErr == dupFNErr)
  542.             this->SendError("rcp: remote directory already exists");
  543.         else
  544.             this->SendError("rcp: couldn't create remote directory");
  545.     }
  546.     
  547.     return (theErr == noErr);
  548. }
  549.  
  550. void
  551. Rcp::UpDir()
  552. {
  553.     short    refNum;
  554.     long    dirID;
  555.  
  556.     HSetVol("\p::", fVRefNum, fDirID);
  557.     HGetVol(nil, &refNum, &dirID);
  558.     
  559.     fDirID = dirID;
  560. }
  561.  
  562. void
  563. Rcp::WriteToFile(char* buf, short len)
  564. {
  565.     char*    beg = buf;
  566.     long    cnt = len;
  567.     char*    end = beg + cnt;
  568.     
  569.     while (beg <= end) {
  570.         if (*beg == '\r')
  571.             *beg = '\n';
  572.             
  573.         beg++;
  574.     }
  575.     
  576.     FSWrite(fFileIORefNum, &cnt, buf);
  577. }
  578.  
  579. pascal void
  580. Notify(    StreamPtr            /*tcpStream*/,
  581.         unsigned short        eventCode,
  582.         Ptr                    userDataPtr,
  583.         unsigned short        /*termReason*/,
  584.         struct ICMPReport*    /*icmpMessage*/    )
  585. {
  586.     if ((eventCode == TCPTerminate) || (eventCode == TCPClosing)) {
  587.         Rcp*    rcp = (Rcp*) userDataPtr;
  588.  
  589.         rcp->DoQuit();
  590.         WakeUpProcess(&rcp->fPSN);
  591.     }
  592. }
  593.